package com.skyable.device.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skyable.common.api.cloud.SaService;
import com.skyable.common.common.ServiceResult;
import com.skyable.common.constants.exception.DeviceExcpConstants;
import com.skyable.common.constants.param.CommonParams;
import com.skyable.common.exceptions.BusinessException;
import com.skyable.device.config.CloudApplicationContext;
import com.skyable.device.entity.DeveloperKey;
import com.skyable.device.entity.DeviceAuthLog;
import com.skyable.device.entity.DomainDeviceInfo;
import com.skyable.device.mapper.DeveloperKeyMapper;
import com.skyable.device.mapper.DeviceAuthLogMapper;
import com.skyable.device.mapper.DeviceBindInfoMapper;
import com.skyable.device.mapper.DomainDeviceInfoMapper;
import com.skyable.device.service.IDeveloperKeyService;
import com.skyable.device.service.IDomainDeviceInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.*;

/**
 * @author GaoYuan
 * @title: DomainDeviceInfoServiceImpl
 * @projectName private-cloud
 * @description: TODO
 * @date 2021/7/316:00
 */
@Slf4j
@Service
public class DomainDeviceInfoServiceImpl extends ServiceImpl<DomainDeviceInfoMapper,DomainDeviceInfo> implements IDomainDeviceInfoService {

    @Autowired
    private SaService saService;
    @Autowired
    DeviceAuthLogMapper deviceAuthLogMapper;
    @Autowired
    DeviceBindInfoMapper deviceBindInfoMapper;

    @Override
    public ServiceResult<DomainDeviceInfo> getDomainDeviceInfoById(String physicalDeviceId) {
        ServiceResult<DomainDeviceInfo> serviceResult = new ServiceResult<>();
        DomainDeviceInfo domainDeviceInfo = baseMapper.selectById(physicalDeviceId);
        serviceResult.setResult(domainDeviceInfo);
        return serviceResult;
    }

    @Override
    public ServiceResult<List<DomainDeviceInfo>> getDomainDeviceInfoList() {
        ServiceResult<List<DomainDeviceInfo>> serviceResult = new ServiceResult<>();
        List<DomainDeviceInfo> domainDeviceInfoList = lambdaQuery().list();
        serviceResult.setResult(domainDeviceInfoList);
        return serviceResult;
    }

    @Override
    public ServiceResult<Map<String,Object>> getDomainDeviceInfoList(DomainDeviceInfo domainDeviceInfo, Integer page, Integer limit) {

        ServiceResult<Map<String,Object>> serviceResult = new ServiceResult<>();

        int offset = (page - 1) * limit;
        Map<String,Object> body = new HashMap<>();
        body.put("offset",offset);
        body.put("count",limit);

        Long subDomainId = null;
        if(domainDeviceInfo != null) {
            subDomainId = domainDeviceInfo.getSubDomainId();
            if (domainDeviceInfo.getOnline() != null && domainDeviceInfo.getOnline() != 0) {
                boolean isOnline = domainDeviceInfo.getOnline() == 1;
                body.put("online", isOnline);
            }
            if (domainDeviceInfo.getActive() != null && domainDeviceInfo.getActive() != 0) {
                boolean isActive = domainDeviceInfo.getActive() == 1;
                body.put("active", isActive);
            }
            if (domainDeviceInfo.getPhysicalDeviceId() != null) {
                String physicalDeviceId = domainDeviceInfo.getPhysicalDeviceId();
                body.put("physicalDeviceId", physicalDeviceId);
            }
        }
        Long domainId = domainDeviceInfo == null ? CloudApplicationContext.domainId.get() : domainDeviceInfo.getDomainId();
        //查询设备列表
        log.info("request interface listDevices params:" + JSONObject.toJSONString(body));
        String result = saService.listDevices(domainId,subDomainId,body);
        log.info("interface listDevices response:" + result);

        //查询设备数量
        log.info("request interface getDeviceCount params:" + JSONObject.toJSONString(body));
        String deviceCountResult = saService.getDeviceCount(domainId, subDomainId, body);
        log.info("interface getDeviceCount response:" + result);

        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj!= null && resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        JSONArray devices = resultObj != null && resultObj.containsKey("devices") ? resultObj.getJSONArray("devices") : new JSONArray();

        JSONObject deviceCountResultObj = JSONObject.parseObject(deviceCountResult);
        if(deviceCountResultObj == null) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_GET_DEVICE_COUNT,DeviceExcpConstants.ERROR_MSG_GET_DEVICE_COUNT);
            return serviceResult;
        }
        if(deviceCountResultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(deviceCountResultObj.getInteger(CommonParams.ERROR_CODE),deviceCountResultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        int deviceCount = deviceCountResultObj.getInteger("count");
        List<DomainDeviceInfo> domainDeviceInfos = devices.toJavaList(DomainDeviceInfo.class);
        Map<String,Object> domainDeviceInfoResult = new HashMap<>();
        domainDeviceInfoResult.put("data",domainDeviceInfos);
        domainDeviceInfoResult.put("count",deviceCount);

        serviceResult.setResult(domainDeviceInfoResult);
        return serviceResult;
    }

    @Override
    public ServiceResult<Map<String,Object>> getDeviceAuthList(DomainDeviceInfo domainDeviceInfo, Integer page, Integer limit) {
        ServiceResult<Map<String,Object>> serviceResult = new ServiceResult<>();
        Map<String,Object> deviceAuthListResult = new HashMap<>(2);
        int offset = (page - 1) * limit;
        Map<String,Object> body = new HashMap<>();
        body.put("offset",offset);
        body.put("count",limit);

        Long domainId = null;
        Long subDomainId = null;
        if(domainDeviceInfo != null) {
            domainId = domainDeviceInfo.getDomainId();
            subDomainId = domainDeviceInfo.getSubDomainId();
            if (domainDeviceInfo.getPhysicalDeviceId() != null) {
                String physicalDeviceId = domainDeviceInfo.getPhysicalDeviceId();
                body.put("physicalDeviceId", physicalDeviceId);
            }
        }
        //查询设备列表
        log.info("request interface listDevices params:" + JSONObject.toJSONString(body));
        String result = saService.listDevices(domainId,subDomainId,body);
        log.info("interface listDevices response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj == null || resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        //查询设备数量
        log.info("request interface getDeviceCount params:" + JSONObject.toJSONString(body));
        String deviceCountResult = saService.getDeviceCount(domainId, subDomainId, body);
        log.info("interface getDeviceCount response:" + result);
        JSONObject deviceCountResultObj = JSONObject.parseObject(deviceCountResult);
        if(deviceCountResultObj == null || deviceCountResultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(deviceCountResultObj.getInteger(CommonParams.ERROR_CODE),deviceCountResultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        //获取设备列表
        JSONArray devices = resultObj.containsKey("devices") ? resultObj.getJSONArray("devices") : new JSONArray();
        //获取设备数量
        int deviceCount = resultObj.containsKey("devices") ? deviceCountResultObj.getInteger("count") : 0;
        List<DomainDeviceInfo> domainDeviceInfos = devices.toJavaList(DomainDeviceInfo.class);
        deviceAuthListResult.put("data",domainDeviceInfos);
        deviceAuthListResult.put("count",deviceCount);
        serviceResult.setResult(deviceAuthListResult);
        return serviceResult;
    }

    @Override
    public ServiceResult<Integer> getDeviceCountByActiveStatus(Long domainId, Long subDomainId) {
        ServiceResult<Integer> serviceResult = new ServiceResult<>();
        Map<String,Object> body = new HashMap<>();
        body.put("active", true);
        log.info("request interface getDeviceCount params:" + JSONObject.toJSONString(body));
        String result = saService.getDeviceCount(domainId,subDomainId,body);
        log.info("interface getDeviceCount response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj == null) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_GET_ACTIVE_DEVICE,DeviceExcpConstants.ERROR_MSG_GET_ACTIVE_DEVICE);
            return serviceResult;
        }
        if(resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        serviceResult.setResult(resultObj.getInteger("count"));
        return serviceResult;
    }

    @Override
    public ServiceResult<Integer> getDeviceCountByOnlineStatus(Long domainId, Long subDomainId) {
        ServiceResult<Integer> serviceResult = new ServiceResult<>();
        Map<String,Object> body = new HashMap<>();
        body.put("online", true);
        log.info("request interface getDeviceCount params:" + JSONObject.toJSONString(body));
        String result = saService.getDeviceCount(domainId,subDomainId,body);
        log.info("interface getDeviceCount response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj == null) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_GET_ONLINE_DEVICE,DeviceExcpConstants.ERROR_MSG_GET_ONLINE_DEVICE);
            return serviceResult;
        }
        if(resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        serviceResult.setResult(resultObj.getInteger("count"));
        return serviceResult;
    }

    @Override
    public ServiceResult<Integer> getDeviceCountByParam(Long domainId, Map<String, Object> params) {
        ServiceResult<Integer> serviceResult = new ServiceResult<>();
        log.info("request interface getDeviceCount params:" + JSONObject.toJSONString(params));
        String result = saService.getDeviceCount(domainId,params);
        log.info("interface getDeviceCount response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj == null) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_GET_ONLINE_DEVICE,DeviceExcpConstants.ERROR_MSG_GET_ONLINE_DEVICE);
            return serviceResult;
        }
        if(resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        serviceResult.setResult(resultObj.getInteger("count"));
        return serviceResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Boolean> importDeviceInfo(DomainDeviceInfo domainDeviceInfo, Long domainId, Map<String, Object> queryMap) {
        return importDeviceInfoList(Collections.singletonList(domainDeviceInfo), domainId, queryMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Boolean> importDeviceInfoList(List<DomainDeviceInfo> devices, Long domainId, Map<String, Object> queryMap) {
        ServiceResult<Boolean> serviceResult = new ServiceResult<>();
        // 1.查看设备是否已经存在
        List<String> deviceIds = new ArrayList<>();
        for (DomainDeviceInfo device : devices) {
            deviceIds.add(device.getPhysicalDeviceId());
        }
        int count = lambdaQuery().in(DomainDeviceInfo::getPhysicalDeviceId,deviceIds).count();
        if(count > 0) {
            log.error("importDeviceInfoList failed,domainDeviceInfo is exist");
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_DEVICE_EXISTS,DeviceExcpConstants.ERROR_MSG_DEVICE_EXISTS);
            return serviceResult;
        }

        List<JSONObject> importDeviceList = new ArrayList<>();
        List<DeviceAuthLog> deviceAuthLogList = new ArrayList<>();
        Long userId = queryMap.get("userId") == null ? null : Long.valueOf(queryMap.get("userId").toString());
        Long subDomainId = queryMap.get("subDomainId") == null ? null : Long.valueOf(queryMap.get("subDomainId").toString());
        for (DomainDeviceInfo device : devices) {
            // 2.创建设备日志
            DeviceAuthLog deviceAutoLog = new DeviceAuthLog();
            deviceAutoLog.setUserId(userId);
            deviceAutoLog.setSubDomain(device.getSubDomainId());
            deviceAutoLog.setSuccess(1);
            deviceAutoLog.setLogType(1);
            deviceAutoLog.setPhysicalDeviceId(device.getPhysicalDeviceId());
            deviceAutoLog.setLogTime(new Date());
            deviceAutoLog.setDetails("设备授权导入,deviceId:" + device.getPhysicalDeviceId());
            deviceAuthLogList.add(deviceAutoLog);

            // 3.创建设备导入信息
            JSONObject importDevice = new JSONObject();
            importDevice.put("physicalDeviceId",device.getPhysicalDeviceId());
            importDevice.put("pubKey",device.getAesKey());
            importDevice.put("devVersion",device.getDevVersion());
            importDevice.put("modVersion",device.getModVersion());
            importDeviceList.add(importDevice);
        }
        // 保存domain_device_info 信息
        this.baseMapper.saveBatchDomainDevice(devices,domainId);
        // 保存日志信息
        this.deviceAuthLogMapper.saveBatchDeviceAuthLog(deviceAuthLogList,domainId);

        // 3.调用api接口
        Map<String,Object> deviceMap = new HashMap<>();
        deviceMap.put("devices", importDeviceList);
        log.info("request interface importDevices params:" + JSONObject.toJSONString(deviceMap));
        String result = saService.importDevices(domainId,subDomainId,deviceMap);
        log.info("interface importDevices response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj == null) {
            //这里需要将异常抛出，让数据库操作进行回滚
            throw new BusinessException(DeviceExcpConstants.ERROR_MSG_IMPORT_API_DEVICE,DeviceExcpConstants.ERROR_CODE_IMPORT_API_DEVICE);
        }
        if(resultObj.containsKey(CommonParams.ERROR_CODE)) {
            //这里需要将异常抛出，让数据库操作进行回滚
            throw new BusinessException(resultObj.getString(CommonParams.ERROR),resultObj.getInteger(CommonParams.ERROR_CODE));
        }
        serviceResult.setResult(true);
        return serviceResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Boolean> deleteDevice(Long domainId, String physicalDeviceId, Map<String, Object> queryMap) {
        // 1.删除云端设备信息
        baseMapper.deleteById(physicalDeviceId);
        // 2.新增删除日志
        Long userId = queryMap.get("userId") == null ? null : Long.valueOf(String.valueOf(queryMap.get("userId")));
        DeviceAuthLog deviceLog = new DeviceAuthLog();
        deviceLog.setUserId(userId);
        deviceLog.setLogType(2);
        deviceLog.setPhysicalDeviceId(physicalDeviceId);
        deviceLog.setLogTime(new Date());
        deviceLog.setDetails("用户["+userId+"]删除设备["+physicalDeviceId+"]");
        deviceLog.setSuccess(1);
        deviceAuthLogMapper.insert(deviceLog);
        // 3.调用api
        ServiceResult<Boolean> serviceResult = new ServiceResult<>();
        log.info("request interface deleteDevice params:{delDeviceId:" + physicalDeviceId + "}");
        String result = saService.deleteDevice(domainId,physicalDeviceId);
        log.info("interface deleteDevice response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if(resultObj != null && resultObj.containsKey(CommonParams.ERROR_CODE)) {
            throw new BusinessException(resultObj.getString(CommonParams.ERROR),resultObj.getInteger(CommonParams.ERROR_CODE));
        }
        serviceResult.setResult(true);
        return serviceResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Boolean> deleteDevices(Long domainId, String[] physicalDeviceIds, Map<String, Object> queryMap) {
        List<String> deviceIds = Arrays.asList(physicalDeviceIds);
        ServiceResult<Boolean> serviceResult = new ServiceResult<>();
        if(!deviceIds.isEmpty()) {
            // 1.删除云端设备信息
            baseMapper.deleteBatchIds(deviceIds);
            // 2.新增删除日志
            Long userId = queryMap.get("userId") == null ? null : (Long) queryMap.get("userId");
            for(String delDeviceId : deviceIds) {
                DeviceAuthLog deviceLog = new DeviceAuthLog();
                deviceLog.setUserId(userId);
                deviceLog.setLogType(2);
                deviceLog.setPhysicalDeviceId(delDeviceId);
                deviceLog.setLogTime(new Date());
                deviceLog.setDetails("用户[" + userId + "]删除设备[" + delDeviceId + "]");
                deviceLog.setSuccess(1);
                deviceAuthLogMapper.insert(deviceLog);

                // 3.调用api
                log.info("request interface deleteDevice params:{delDeviceId:" + delDeviceId + "}");
                String result = saService.deleteDevice(domainId, delDeviceId);
                log.info("interface deleteDevice response:" + result);
                JSONObject resultObj = JSONObject.parseObject(result);
                if (resultObj != null && resultObj.containsKey(CommonParams.ERROR_CODE)) {
                    throw new BusinessException(DeviceExcpConstants.ERROR_MSG_DELETE_DEVICE,DeviceExcpConstants.ERROR_CODE_DELETE_DEVICE);
                }
            }
            serviceResult.setResult(true);
        } else {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_DEVICE_EMPTY,DeviceExcpConstants.ERROR_MSG_DEVICE_EMPTY);
            return serviceResult;
        }
        return serviceResult;
    }

    @Override
    public ServiceResult<Integer> createDomainDeviceTable(Long domainId) {
        ServiceResult<Integer> serviceResult = new ServiceResult<>();
        try {
            //设备信息表
            baseMapper.createDeviceInfoTable(domainId);
            //设备授权信息表
            deviceAuthLogMapper.createDeviceAuthLogTable(domainId);
            //设备绑定表
            deviceBindInfoMapper.createDeviceBindInfoTable(domainId);
            return serviceResult;
        } catch (Exception be) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_CREATE_DEVICE_TABLE,DeviceExcpConstants.ERROR_MSG_CREATE_DEVICE_TABLE);
            return serviceResult;
        }
    }

    @Override
    public ServiceResult<List<String>> listDeviceVersions(Long domainId, Long subDomainId, String otaType) {
        ServiceResult<List<String>> serviceResult = new ServiceResult<>();
        Map<String,Object> body = new HashMap<>();
        body.put("type",otaType);
        log.info("request interface listDeviceVersions params:" + JSONObject.toJSONString((body)));
        String result = saService.listDeviceVersions(domainId, subDomainId, body);
        log.info("interface listDeviceVersions response:" + result);
        JSONObject resultObj = JSONObject.parseObject(result);
        if (resultObj == null) {
            serviceResult.setError(DeviceExcpConstants.ERROR_CODE_LIST_DEVICE_VERSION,DeviceExcpConstants.ERROR_MSG_LIST_DEVICE_VERSION);
            return serviceResult;
        }
        if (resultObj.containsKey(CommonParams.ERROR_CODE)) {
            serviceResult.setError(resultObj.getInteger(CommonParams.ERROR_CODE),resultObj.getString(CommonParams.ERROR));
            return serviceResult;
        }
        JSONArray deviceVersionArray = resultObj.getJSONArray("versions");
        List<String> deviceVersionList = deviceVersionArray.toJavaList(String.class);
        serviceResult.setResult(deviceVersionList);
        return serviceResult;
    }

}
